Skip to content

Resolve type variables in resolver parameter types - #882

Merged
oryan-block merged 1 commit into
masterfrom
bugfix/880
Oct 19, 2026
Merged

oryan-block merged 1 commit into
masterfrom
bugfix/880

Conversation

@oryan-block

Copy link
Copy Markdown
Collaborator

Fixes #880

Checklist

  • Pull requests follows the contribution guide
  • New or modified functionality is covered by tests

Description

A resolver method inherited from a generic class, with the class's type variable as its parameter, built fine but failed on every query:

abstract class InputResolver<I> : GraphQLQueryResolver {
    fun generic(input: I): String = "generic got $input"
}

class GreetingQuery : InputResolver<GreetingInput>()

Exception while fetching data (/generic) : class sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to class java.lang.Class

The scanner resolves I to GreetingInput in TypeClassMatcher, so the build passes. The data fetcher took MethodFieldResolver#getMethodParameterType as is, which is the raw I from Method#getGenericParameterTypes, and shouldValueBeConverted cast it to Class in JavaType.unwrap(). ArgumentConverter got the raw I too, which Jackson reads as Object, so I think fixing only the cast would have handed the method a Map.

So getMethodParameterType now resolves the type variables against the resolver class with GenericTypeResolver#resolveTypeVariables (no longer private). Every caller gets the resolved type, so the scanner and the data fetcher start from the same one. I also dropped the ?.apply { typeResolver.getRawClass(this) } in createDataFetcher, since its result was thrown away.

I tried GenericTypeResolver#resolve first, but it also unwraps generic wrappers and boxes primitives. That broke ResolverMethodsTest.testOmittedBooleanArgument: an omitted argument for a boolean parameter became null instead of false, and the call failed. resolveTypeVariables only replaces the type variables, and TypeClassMatcher still calls resolve on top of it for the scan.

The unmapped input field check from #857 reads the same type, so it now checks inputs typed by a type variable too. Before, they weren't checked. So the generic case in UnmappedInputFieldsTest moves from the "can't be checked" test to the one that reports, and the Query.generic exclusion from #879 is gone.

Added a case with the issue's schema to GenericResolverTest. It failed with the cast error before the fix. mvn clean verify passes on JDK 25, on JDK 25 against graphql-java 25.1, and on JDK 11. Also checked through the public API: { generic(input: { name: "a" }) } failed on master on graphql-java 26.1 and 25.1, and returns generic got GreetingInput(name=a) on both with this change.

@sonarqubecloud

Copy link
Copy Markdown

@oryan-block
oryan-block merged commit d4232ba into master Oct 19, 2026
7 checks passed
@oryan-block
oryan-block deleted the bugfix/880 branch October 19, 2026 00:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resolver parameter typed by the resolver's own type variable fails on every query

1 participant